package com.cmpe451.nutty.dao;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import com.cmpe451.nutty.model.BaseModel;
import com.cmpe451.nutty.model.Comment;
import com.cmpe451.nutty.model.Favorite;
import com.cmpe451.nutty.model.Ingredients;
import com.cmpe451.nutty.model.Menu;
import com.cmpe451.nutty.model.Menu_Recipe;
import com.cmpe451.nutty.model.Rate;
import com.cmpe451.nutty.model.Recipe;
import com.cmpe451.nutty.model.Recipe_Derive;
import com.cmpe451.nutty.model.Style;
import com.cmpe451.nutty.model.Tools;
import com.cmpe451.nutty.model.Unit;
import com.cmpe451.nutty.so.GuiUser;

/**
 * Recipe dao contains the database access elements for recipes.
 * @author CmpE Group 2 Fall 2014 nuttyconfirmation@gmail.com
 *
 */
@Repository
public class RecipeDaoImpl extends BaseDaoImpl implements RecipeDao, BaseDao {

	@SuppressWarnings("unchecked")
	@Override
	public List<Recipe> findRecipeByUser(GuiUser user) {

		Criteria criteria = createCriteria(Recipe.class);
		criteria.add(Restrictions.eq("recipe_owner", user.getUsername()));
		return criteria.list();
	}

	@Override
	public Recipe findRecipeById(Long id) {
		// TODO Auto-generated method stub
		// id = (long)id;
		return getHibernateTemplate().get(Recipe.class, id);
	}

	@Override
	public Ingredients findIngredientById(long id) {
		// TODO Auto-generated method stub
		return getHibernateTemplate().get(Ingredients.class, id);
	}

	@Override
	public Tools findToolByName(String name) {
		// TODO Auto-generated method stub
		Criteria criteria = createCriteria(Tools.class);
		criteria.add(Restrictions.eq("name", name));
		return (Tools) criteria.uniqueResult();
	}

	@Override
	public Tools findToolById(Long id) {
		// TODO Auto-generated method stub
		return getHibernateTemplate().get(Tools.class, id);
	}

	@Override
	public Ingredients findIngredientByName(String name) {
		// TODO Auto-generated method stub
		Criteria criteria = createCriteria(Ingredients.class);
		criteria.add(Restrictions.eq("name", name));
		return (Ingredients) criteria.uniqueResult();
	}

	@SuppressWarnings("unchecked")
	public List<Recipe> findLatestRecipes() {

		Criteria criteria = createCriteria(Recipe.class);
		criteria.addOrder(Order.desc("createDate"));
		criteria.setMaxResults(20);
		List<Recipe> temp = criteria.list();
			Collections.sort(temp, new Comparator<Recipe>() {
				@Override
				public int compare(Recipe o1, Recipe o2) {
					return o2.getRate().compareTo(o1.getRate());
				}
			});

		return temp;

	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Comment> getLatestCommentsById(Long recipeId) {
		// TODO Auto-generated method stub
		Criteria criteria = createCriteria(Comment.class);

		criteria.add(Restrictions.eq("recipe_id", recipeId));
		criteria.setMaxResults(10);
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Recipe> findRecipeByQuery(String query) {
		Criteria criteria = createCriteria(Recipe.class);
		criteria.add(Restrictions
				.like("recipe_name", query, MatchMode.ANYWHERE));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Unit> findUnits() {
		Criteria criteria = createCriteria(Unit.class);
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Recipe> findLatestRecipesByUsername(String username) {
		Criteria criteria = createCriteria(Recipe.class);
		criteria.add(Restrictions.like("recipe_owner", username));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Style> findStyles() {
		Criteria criteria = createCriteria(Style.class);
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Recipe> findLatestRecipesInCircle(List<String> follows) {
		Criteria criteria = createCriteria(Recipe.class);
		criteria.add(Restrictions.in("recipe_owner", follows));
		criteria.addOrder(Order.desc("updateDate"));
		criteria.setMaxResults(10);
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Tools> findTools() {
		Criteria criteria = createCriteria(Tools.class);
		return criteria.list();
	}

	@Override
	public Rate getRatebyRecipe(String username, Long recipeId) {
		Criteria criteria = createCriteria(Rate.class);
		criteria.add(Restrictions.eq("username", username));
		criteria.add(Restrictions.eq("recipe_id", recipeId));
		return (Rate) criteria.uniqueResult();
	}

	@Override
	public List<Recipe> rateLatestRecipes(List<Recipe> recipes) {
		// TODO Auto-generated method stub
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Rate> getTotalRate(Recipe recipe) {
		// TODO Auto-generated method stub
		Criteria criteria = createCriteria(Rate.class);
		criteria.add(Restrictions.eq("recipe_id", recipe.getId()));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Recipe> getLikedRecipes(String str, int cooktime,
			String easiness) {
		// TODO Auto-generated method stub
		Criteria criteria = createCriteria(Recipe.class);
		criteria.add(Restrictions.like("ingredients_list", str,
				MatchMode.ANYWHERE));
		criteria.add(Restrictions.lt("cook_time", cooktime));
		criteria.add(Restrictions.eq("easiness", easiness));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Recipe> getDislikedRecipes(String str, int cooktime,
			String easiness) {
		// TODO Auto-generated method stub
		Criteria criteria = createCriteria(Recipe.class);
		criteria.add(Restrictions.not(Restrictions.like("ingredients_list",
				str, MatchMode.ANYWHERE)));
		criteria.add(Restrictions.lt("cook_time", cooktime));
		criteria.add(Restrictions.eq("easiness", easiness));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Recipe> getRecipeBasedOnKeywords(String str) {
		// TODO Auto-generated method stub
		Criteria criteria = createCriteria(Recipe.class);
		criteria.add(Restrictions.like("ingredients_list", str,
				MatchMode.ANYWHERE));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Recipe> getLikedRecipes(String str) {
		// TODO Auto-generated method stub
		Criteria criteria = createCriteria(Recipe.class);
		criteria.add(Restrictions.like("ingredients_list", str,
				MatchMode.ANYWHERE));
		return criteria.list();
	}

	@Override
	public Favorite findFav(Long userId, Long recipeId) {
		// TODO Auto-generated method stub
		Criteria criteria = createCriteria(Favorite.class);
		criteria.add(Restrictions.eq("user_id", userId));
		criteria.add(Restrictions.eq("recipe_id", recipeId));
		return (Favorite) criteria.uniqueResult();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Recipe> getDislikedRecipes(String str) {
		// TODO Auto-generated method stub
		Criteria criteria = createCriteria(Recipe.class);
		criteria.add(Restrictions.not(Restrictions.like("ingredients_list",
				str, MatchMode.ANYWHERE)));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Favorite> findFavorite(Long userId) {
		Criteria criteria = createCriteria(Favorite.class);
		criteria.add(Restrictions.eq("user_id", userId));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Menu> findMenusOfTheUser(long userid) {
		Criteria criteria = createCriteria(Menu.class);
		criteria.add(Restrictions.eq("userId", userid));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Menu_Recipe> findMenuRecipePairs(Long menuid) {
		Criteria criteria = createCriteria(Menu_Recipe.class);
		criteria.add(Restrictions.eq("menuId", menuid));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Recipe> findRecipeByName(String name) {
		Criteria criteria = createCriteria(Recipe.class);
		criteria.add(Restrictions.like("recipe_name", name));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Recipe_Derive> getDerivedRecipesById(Long recipeId) {
		Criteria criteria = createCriteria(Recipe_Derive.class);
		criteria.add(Restrictions.eq("current_recipe", recipeId));
		return criteria.list();
	}
}
